home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Games Collection 1 / software vault.zip / software vault / CDR10 / YICN23.ZIP / SOURCE / PLAY_CMF.C < prev    next >
C/C++ Source or Header  |  1992-04-05  |  8KB  |  369 lines

  1. /*
  2.  * Copyrighted as an unpublished work.
  3.  * (c) Copyright 1991 Brian Smith
  4.  * All rights reserved.
  5.  *
  6.  * Read the LICENSE file for details on distribution and use.
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <fcntl.h>
  12. #include <dos.h>
  13. #include <alloc.h>
  14. #include <io.h>
  15. #include <string.h>
  16.  
  17. #include "sb.h"
  18.  
  19. #define TRUE  1
  20. #define FALSE 0
  21.  
  22. #define lobyte(X)   (((unsigned char *)&X)[0])
  23. #define hibyte(X)   (((unsigned char *)&X)[1])
  24.  
  25. /* Globals */
  26. int fm_herz;        /* clock ticks per second */
  27. int tempo;          /* clock ticks per quarter note */
  28. int fm_fd;
  29. int note_on[22];
  30. char **instrument_table;
  31. int note_table[12] = {
  32.     343,
  33.     363,
  34.     385,
  35.     408,
  36.     432,
  37.     458,
  38.     485,
  39.     514,
  40.     544,
  41.     577,
  42.     611,
  43.     647
  44.     };
  45.  
  46.  
  47. int main(argc, argv)
  48. int argc;
  49. char **argv;
  50. {
  51.     int cmf_fd;
  52.  
  53.     if (argc != 2)
  54.     {
  55.         printf("usage: %s <cmf file>\n", argv[0]);
  56.         exit(-1);
  57.     }
  58.  
  59.     /* open cmf file */
  60.     cmf_fd = open(argv[1], O_RDONLY);
  61.     if (cmf_fd == -1)
  62.     {
  63.         printf("usage: %s <cmf file>\n", argv[0]);
  64.         exit(-1);
  65.     }
  66.  
  67.     /* verify that file is a cmf file */
  68.     if (!verify_cmf(cmf_fd))
  69.     {
  70.         printf("file was not a cmf file\n");
  71.         printf("usage: %s <cmf file>\n", argv[0]);
  72.         exit(-1);
  73.     }
  74.  
  75.     /* read and set instruments from cmf file */
  76.     get_instruments(cmf_fd);
  77.  
  78.     /* get timing */
  79.     set_timing(cmf_fd);
  80.  
  81.     /* open soundblaster fm chips */
  82.     Sb_FM_Reset();
  83.  
  84.     /* play song */
  85.     play_song(cmf_fd);
  86.  
  87.     return(0);
  88. }
  89.  
  90.  
  91. /* check for "CTMF" in first four bytes of file */
  92. int verify_cmf(fd)
  93. int fd;
  94. {
  95.     char idbuf[5];
  96.  
  97.     /* get id */
  98.     lseek(fd, 0, SEEK_SET);
  99.     if (read(fd, idbuf, 4) != 4)
  100.         return(FALSE);
  101.     
  102.     /* compare to standard id */
  103.     idbuf[4] = (char)0;
  104.     if (strcmp(idbuf, "CTMF") != 0)
  105.         return(FALSE);
  106.     
  107.     return(TRUE);
  108. }
  109.  
  110. int get_instruments(fd)
  111. int fd;
  112. {
  113.     int offset;
  114.     int num_instruments;
  115.     int i;
  116.     int rc;
  117.     int fnum, block, note;
  118.     unsigned char tmp_byte;
  119.  
  120.     /* get offset of instrument block */
  121.     offset = 0;
  122.     lseek(fd, 0x06, SEEK_SET);
  123.     read(fd, &tmp_byte, 1);
  124.     lobyte(offset) = tmp_byte;
  125.     read(fd, &tmp_byte, 1);
  126.     hibyte(offset) = tmp_byte;
  127.  
  128.     /* get number of instruments */
  129.     num_instruments = 0;
  130.     lseek(fd, 0x24, SEEK_SET);
  131.     read(fd, &tmp_byte, 1);
  132.     lobyte(num_instruments) = tmp_byte;
  133.     read(fd, &tmp_byte, 1);
  134.     hibyte(num_instruments) = tmp_byte;
  135.  
  136.     /* allocate space */
  137.     instrument_table = (char **)malloc(sizeof(int *) * num_instruments);
  138.  
  139.     /* read each instrument */
  140.     lseek(fd, (long)offset, SEEK_SET);
  141.     for (i=0; i< num_instruments; i++)
  142.     {
  143.         /* allocate space */
  144.         instrument_table[i] = (char *)malloc(16);
  145.  
  146.         /* set instrument characteristics */
  147.         read(fd, instrument_table[i], 16);
  148.     }
  149.  
  150.     return(0);
  151. }
  152.  
  153.  
  154. /*
  155.  * get and set timing parameters
  156.  */
  157. int set_timing(fd)
  158. int fd;
  159. {
  160.     unsigned char tmp_byte;
  161.  
  162.     /* get tempo */
  163.     tempo = 0;
  164.     lseek(fd, 0x0C, SEEK_SET);
  165.     read(fd, &tmp_byte, 1);
  166.     tempo = (unsigned int)tmp_byte;
  167.     read(fd, &tmp_byte, 1);
  168.     tempo += (unsigned int)tmp_byte << 8;
  169.  
  170.     /* get herz of timing clock */
  171.     fm_herz = 0;
  172.     lseek(fd, 0x0C, SEEK_SET);
  173.     read(fd, &tmp_byte, 1);
  174.     fm_herz = (unsigned int)tmp_byte;
  175.     read(fd, &tmp_byte, 1);
  176.     fm_herz += (unsigned int)tmp_byte << 8;
  177.     
  178.     return(0);
  179. }
  180.  
  181.  
  182. /*
  183.  * seek to the midi stream and handle midi events for the song
  184.  */
  185. int play_song(fd)
  186. int fd;
  187. {
  188.     int offset;
  189.     unsigned char tmp_byte;
  190.     int delta;
  191.  
  192.     /* get offset of music stream */
  193.     lseek(fd, 8, SEEK_SET);
  194.     read(fd, &tmp_byte, 1);
  195.     offset = (unsigned int)tmp_byte;
  196.     read(fd, &tmp_byte, 1);
  197.     offset += (unsigned int)tmp_byte << 8;
  198.     lseek(fd, offset, SEEK_SET);
  199.  
  200.     /* process till EOF */
  201.     while(1)
  202.     {
  203.         /* get delta time */
  204.         delta = ReadVarLen(fd);
  205.         if (delta == -1)
  206.             break;
  207.  
  208.         /* wait delta */
  209.         if (delta > 0)
  210.         delay((double)delta/(double)fm_herz * 1000);
  211.  
  212.         /* process midi event */
  213.         process_event(fd, delta);
  214.     }
  215.  
  216.  
  217.     return(0);
  218. }
  219.  
  220.  
  221. /*
  222.  * read a variable length scalar in MIDI format
  223.  */
  224. int ReadVarLen(fd)
  225. int fd;
  226. {
  227.     int value;
  228.     unsigned char tmp_byte;
  229.  
  230.     if (read(fd, &tmp_byte, 1) == 0)
  231.         return(-1);
  232.     value = (int)tmp_byte;
  233.     if (tmp_byte & 0x80)
  234.     {
  235.         value &= 0x7F;
  236.         do
  237.         {
  238.             if (read(fd, &tmp_byte, 1) == 0)
  239.                 return(-1);
  240.             value = (value << 7) + (tmp_byte & 0x7F);
  241.         } while (tmp_byte & 0x80);
  242.     }
  243.  
  244.     return(value);
  245. }
  246.  
  247.  
  248. /*
  249.  * process a midi event
  250.  */
  251. int process_event(fd, delta)
  252. int fd;
  253. {
  254.     int rc, channel;
  255.     unsigned char tmp_byte;
  256.     static int status = -1;
  257.  
  258.     /* get status byte */
  259.     read(fd, &tmp_byte, 1);
  260.     if (tmp_byte & 0x80)
  261.     {
  262.         status = (unsigned int)tmp_byte;
  263.     }
  264.     else
  265.     {
  266.         /* running status, so back up one */
  267.         if (status == -1)
  268.         {
  269.             printf("ERROR in cmf file. Running status at beginning of file\n");
  270.             exit(-1);
  271.         }
  272.         lseek(fd, -1, SEEK_CUR);
  273.     }
  274.     
  275.     /* switch different events */
  276.     switch (status & 0xF0)
  277.     {
  278.         case 0x80:
  279.             /* turn note off */
  280.         channel = status & 0x0f;
  281.         Sb_FM_Key_Off(channel);
  282.         note_on[channel] = 0;
  283.  
  284.             /* waste two bytes */
  285.             read(fd, &tmp_byte, 1);
  286.             read(fd, &tmp_byte, 1);
  287.             break;
  288.         case 0x90:
  289.             /* get note */
  290.             read(fd, &tmp_byte, 1);
  291.             /* determine note */
  292.  
  293.             /* turn note on */
  294.         channel = status & 0x0f;
  295.         if (note_on[channel])
  296.         Sb_FM_Key_Off(channel);
  297.         note_on[channel] = 1;
  298.         Sb_FM_Key_On(channel,note_table[tmp_byte % 12],(tmp_byte/12) & 7);
  299.  
  300.             /* waste a bytes */
  301.             read(fd, &tmp_byte, 1);
  302.             break;
  303.         case 0xA0:
  304.             printf("polyphonic key pressure: not handled\n");
  305.             /* waste two bytes */
  306.             read(fd, &tmp_byte, 1);
  307.             read(fd, &tmp_byte, 1);
  308.             break;
  309.         case 0xB0:
  310.             printf("control change: not handled\n");
  311.             /* waste two bytes */
  312.             read(fd, &tmp_byte, 1);
  313.             read(fd, &tmp_byte, 1);
  314.             break;
  315.         case 0xC0:
  316.             /* change the instrument on a channel */
  317.             read(fd, &tmp_byte, 1);
  318.             load_instrument(status&0x0F, tmp_byte & 0x0F);
  319.             break;
  320.         case 0xD0:
  321.             printf("Channel Pressure: not handled\n");
  322.             /* waste a byte */
  323.             read(fd, &tmp_byte, 1);
  324.             break;
  325.         case 0xE0:
  326.             printf("Pitch Wheel Change: not handled\n");
  327.             /* waste two bytes */
  328.             read(fd, &tmp_byte, 1);
  329.             read(fd, &tmp_byte, 1);
  330.             break;
  331.         case 0xF0:
  332.             printf("System Exclusive: not handled\n");
  333.             /* waste two bytes */
  334.             read(fd, &tmp_byte, 1);
  335.             read(fd, &tmp_byte, 1);
  336.             break;
  337.         default:
  338.             printf("internal program error\n");
  339.             /* waste two bytes */
  340.             read(fd, &tmp_byte, 1);
  341.             read(fd, &tmp_byte, 1);
  342.             break;
  343.     }
  344.  
  345.  
  346.     return(0);
  347. }
  348.  
  349.  
  350. /*
  351.  * load an instrument from the instrument table into the SoundBlaster
  352.  */
  353. int load_instrument(channel, instrument)
  354. {
  355.     int rc;
  356.  
  357.     /* error check! */
  358.     if ((channel <0) || (channel >= 9))
  359.         return;
  360.  
  361.     /* abort instrument if being loaded */
  362.     if (note_on[channel])
  363.     Sb_FM_Key_Off(channel);
  364.  
  365.     /* set instrument characteristics */
  366.     Sb_FM_Set_Voice(channel,instrument_table[instrument]);
  367.     return(0);
  368. }
  369.